package top.cardone.context;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import top.cardone.core.util.action.Action0;
import top.cardone.core.util.action.Action1;
import top.cardone.core.util.func.Func0;
import top.cardone.core.util.func.Func1;

/**
 * 上下文支持
 *
 * @author yao hai tao
 */
@lombok.extern.log4j.Log4j2
public class ApplicationContextHolder implements ApplicationContextAware {
    /**
     * Spring ApplicationContext
     */
    @lombok.Getter
    private static ApplicationContext applicationContext;

    /**
     * 执行有返回值
     *
     * @param requiredType 类型
     * @param action       执行方法
     * @param names        名称
     * @param <T1>         bean 类型
     * @return
     */
    public static <T1> void action(Class<T1> requiredType, Action1<T1> action, String... names) {
        action(requiredType, action, null, names);
    }

    /**
     * 执行有返回值
     *
     * @param requiredType 类型
     * @param action       执行方法
     * @param names        名称
     * @param <T1>         bean 类型
     * @return
     */
    public static <T1> void action(Class<T1> requiredType, Action1<T1> action, Action0 defaultAction, String... names) {
        T1 t1 = getBean(requiredType, names);

        if (t1 == null) {
            if (defaultAction != null) {
                defaultAction.action();
            }

            return;
        }

        action.action(t1);
    }

    /**
     * 执行有返回值
     *
     * @param names 名称
     * @return
     */
    public static void action(Action1<Object> action, String... names) {
        action(Object.class, action, null, names);
    }

    /**
     * 执行有返回值
     *
     * @param names 名称
     * @return
     */
    public static void action(Action1<Object> action, Action0 defaultAction, String... names) {
        action(Object.class, action, defaultAction, names);
    }

    /**
     * 执行有返回值
     *
     * @param requiredType 类型
     * @param func         执行方法
     * @param names        名称
     * @param <R1>         返回类型
     * @param <T1>         bean 类型
     * @return
     */
    public static <R1, T1> R1 func(Class<T1> requiredType, Func1<R1, T1> func, String... names) {
        return func(requiredType, func, null, names);
    }

    /**
     * 执行有返回值
     *
     * @param requiredType 类型
     * @param func         执行方法
     * @param names        名称
     * @param <R1>         返回类型
     * @param <T1>         bean 类型
     * @return
     */
    public static <R1, T1> R1 func(Class<T1> requiredType, Func1<R1, T1> func, Func0<R1> defaultFunc, String... names) {
        T1 t1 = getBean(requiredType, names);

        if (t1 == null) {
            if (defaultFunc == null) {
                return null;
            }

            return defaultFunc.func();
        }

        return func.func(t1);
    }

    /**
     * 执行有返回值
     *
     * @param func  执行方法
     * @param names 名称
     * @param <R1>  返回类型
     * @return
     */
    public static <R1> R1 func(Func1<R1, Object> func, String... names) {
        return func(Object.class, func, null, names);
    }

    /**
     * 执行有返回值
     *
     * @param func  执行方法
     * @param names 名称
     * @param <R1>  返回类型
     * @return
     */
    public static <R1> R1 func(Func1<R1, Object> func, Func0<R1> defaultFunc, String... names) {
        return func(Object.class, func, defaultFunc, names);
    }

    /**
     * 获取 bean
     *
     * @param requiredType 类型
     * @param names        名称
     * @return bean
     */
    public static <T> T getBean(final Class<T> requiredType, String... names) {
        return getBean(requiredType, false, names);
    }

    /**
     * 获取 bean
     *
     * @param requiredType 类型
     * @param append       附加
     * @param names        名称
     * @param <T>
     * @return
     */
    public static <T> T getBean(final Class<T> requiredType, boolean append, String... names) {
        if (applicationContext == null) {
            return null;
        }

        if (ArrayUtils.isEmpty(names)) {
            names = new String[]{requiredType.getName()};
        }

        for (String name : names) {
            if (StringUtils.isBlank(name)) {
                continue;
            }

            if (append) {
                name = requiredType.getName() + name;
            }

            if (!applicationContext.containsBean(name)) {
                continue;
            }

            return applicationContext.getBean(name, requiredType);
        }

        if (log.isErrorEnabled()) {
            for (String name : names) {
                log.error("未找到对应的bean:" + name);
            }
        }

        return null;
    }

    /**
     * 获取 bean
     *
     * @param names 名称集合
     * @return bean
     */
    public static Object getBean(final String... names) {
        return getBean(Object.class, names);
    }

    /**
     * 设置应用上下文
     *
     * @param applicationContext
     * @throws BeansException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        ApplicationContextHolder.applicationContext = applicationContext;
    }
}